package hu.jonas.allunit.source;

import hu.jonas.allunit.PluginHelper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchMatch;
import org.eclipse.jdt.core.search.SearchParticipant;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;

public class JavaUtils {

	private static PluginHelper javaCoreHelper = new PluginHelper();
	
	// TODO: we should provide project name if there is two classes with the same name
	
	public static IMethod findJavaMethodByName(String className, String methodName) {
		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
		IJavaModel javaModel = javaCoreHelper.create(workspaceRoot);
		
		try {
			IJavaProject[] javaProjects = javaModel.getJavaProjects();
			for (IJavaProject javaProject : javaProjects) {
				IType type = javaProject.findType(className);
				
				if (type != null) {
					IMethod[] methods = type.getMethods();
					for (IMethod method : methods) {
						if (method.getElementName().equals(methodName)) {
							return method;
						}
					}
				}
			}
		} catch (JavaModelException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	public static void openEditorWithJavaMethod(IMethod method)
			throws PartInitException, JavaModelException {
		
		ICompilationUnit compilationUnit = method.getCompilationUnit();
		IEditorPart editorPart = JavaUI.openInEditor(compilationUnit);
		JavaUI.revealInEditor(editorPart, (IJavaElement) method);
	}
	
	public static IMethod[] findTestMethodsInWorkspace() throws CoreException {
		List<IMethod> methods = new ArrayList<IMethod>(Arrays.asList(findJUnit4TestMethodsInWorkspace()));
		methods.addAll(Arrays.asList(findJUnit3TestMethodsInWorkspace()));
		
		return methods.toArray(new IMethod[0]);
	}
	
	public static IMethod[] findJUnit4TestMethodsInWorkspace() throws CoreException {
		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
		IJavaModel javaModel = javaCoreHelper.create(workspaceRoot);
		IJavaProject[] javaProjects = javaModel.getJavaProjects();
	
		SearchEngine search = new SearchEngine();
		SearchPattern pattern = SearchPattern.createPattern(
				"org.junit.Test",
				IJavaSearchConstants.ANNOTATION_TYPE,
				IJavaSearchConstants.ANNOTATION_TYPE_REFERENCE,
				SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE
			);
			
		SearchParticipant[] participants = new SearchParticipant[] {
				SearchEngine.getDefaultSearchParticipant()
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(javaProjects, IJavaSearchScope.SOURCES);
		
		final Set<IMethod> testMethods = new HashSet<IMethod>();
		
		SearchRequestor requestor = new SearchRequestor() {
			
			@Override
			public void acceptSearchMatch(SearchMatch match) throws CoreException {
				Object element = match.getElement();
				
				if (element instanceof IMethod) {
					IMethod method = (IMethod) element;
					
					testMethods.add(method);
				}
			}
		};

		search.search(pattern, participants, scope, requestor, null);
		
		return testMethods.toArray(new IMethod[0]);
	}
	
	public static IMethod[] findJUnit3TestMethodsInWorkspace() throws CoreException {
		IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
		IJavaModel javaModel = javaCoreHelper.create(workspaceRoot);
		IJavaProject[] javaProjects = javaModel.getJavaProjects();
	
		SearchEngine search = new SearchEngine();
		SearchPattern pattern = SearchPattern.createPattern(
				"test* void",
				IJavaSearchConstants.METHOD,
				IJavaSearchConstants.DECLARATIONS,
				SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE
			);
		SearchParticipant[] participants = new SearchParticipant[] {
				SearchEngine.getDefaultSearchParticipant()
		};
		IJavaSearchScope scope = SearchEngine.createJavaSearchScope(javaProjects, IJavaSearchScope.SOURCES);
		
		final Set<IMethod> testMethods = new HashSet<IMethod>();
		
		SearchRequestor requestor = new SearchRequestor() {
			
			@Override
			public void acceptSearchMatch(SearchMatch match) throws CoreException {
				Object element = match.getElement();
				
				if (element instanceof IMethod) {
					IMethod method = (IMethod) element;
					
					// public and not static ???
					
					testMethods.add(method);
				}
			}
		};

		search.search(pattern, participants, scope, requestor, null);
		
		return testMethods.toArray(new IMethod[0]);
	}
}
